<template>
  <div>
    <!--
      (I)第9步：为页面提供一个表单，用来让用户填写查询条件的信息的，使用ElementUI提供好的模板
      teacherQuery里面封装了：
      讲师姓名name、讲师级别level、开始时间joinDateBegin、结束时间joinDateEnd
      双绑v-model，绑定的也是这4个属性
      (j)第10步：为查询、清空两个按钮，绑定单击响应事件，也就是为query、clear提供相应的方法
    -->
    <el-form :inline="true" class="demo-form-inline" style="margin:15px">
      <el-form-item>
        <el-input v-model="teacherQuery.name" placeholder="讲师姓名"/>
      </el-form-item>
      <el-form-item>
        <el-select v-model="teacherQuery.level" placeholder="讲师级别">
          <el-option value="2" label="首席讲师"/>
          <el-option value="1" label="高级讲师"/>
        </el-select>
      </el-form-item>
      <el-form-item label="入驻时间:">
        <el-date-picker
          v-model="teacherQuery.joinDateBegin"
          type="date"
          placeholder="开始时间"/>
        -
        <el-date-picker
          v-model="teacherQuery.joinDateEnd"
          type="date"
          placeholder="结束时间"/>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="query">查询</el-button>
        <el-button @click="clear">清空</el-button>
      </el-form-item>
    </el-form>
    <!--
        执行流程：
        当页面打开时，钩子函数created()就会被执行，
        this.getTeachersList()也随之会被加载，向后端发送请求，请求成功后，
        将得到的响应对象，赋值给data中的teacherList
        这样teacherList就初始化成功
        然后就会往div容器进行渲染，显示数据
    -->
    <!-- （4）第四步：html渲染数据，对Vue对象拿到的数组数据teacherList进行遍历渲染 -->
    <!-- 使用ElementUI提供好的模板 -->
    <el-button type="danger" size="mini" style="margin-bottom: 10px" @click="batchRemove()">批量删除</el-button>
    <el-table :data="teacherList" border style="width: 100%" @selection-change="handleSelectionChange">
      <!--
      为表格添加一个多选框，用于批量删除，为批量删除绑定单击事件@click="batchRemove
      同时为表格绑定一个选择框改变事件@selection-change="handleSelectionChange"
      为什么要为表格绑定一个选择框改变事件呢？
      因为要收集用户选中选择框的信息，里面封装了每一行数据的id
      -->
      <el-table-column
        type="selection"
        width="55"/>
      <el-table-column type="index" width="50"/>
      <el-table-column label="头像" width="80">
        <template slot-scope="scope">
          <!-- scope代表范围对象，row代表当前行数据，也就是一个teacher对象，avatar是teacher对象里面的属性 -->
          <!-- 对avatar进行判断，如果有值，则显示所上传的图片 -->
          <img v-if="scope.row.avatar" :src="scope.row.avatar" style="width:60px;height:60px;" alt="">
          <!-- 对avatar进行判断，如果没有值，则显示默认的图片 -->
          <img v-else src="https://guli-file-austin.oss-cn-shanghai.aliyuncs.com/avatar/2021/02/01/2020-2-13%2084826%202.jpg" style="width:60px;height:60px;" alt="">
        </template>
      </el-table-column>
      <el-table-column prop="name" label="名称" width="80" />
      <el-table-column label="头衔" width="90">
        <template slot-scope="scope">
          <el-tag v-if="scope.row.level === 1" type="success" size="mini">高级讲师</el-tag>
          <el-tag v-if="scope.row.level === 2" size="mini">首席讲师</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="intro" label="简介" />
      <el-table-column prop="sort" label="排序" width="60" />
      <el-table-column prop="joinDate" label="入驻时间" width="160" />
      <!-- 使用ElementUI提供好的模板，为页面提供【删除】和【编辑】按钮 -->
      <el-table-column label="操作">
        <!--
          socpe代表范围对象，是指当前遍历生成标签生成表格时当前范围的对象
          "删除"按钮绑定了单击响应事件handleDelete(scope.$index, scope.row)，
          点击时，会到methods属性找对应的方法handleDelete()
          所以，我们要提供相应的方法
          当表格中的方法handleDelete(scope.$index, scope.row)被回调时，它会进行传参
          传参给methods中的方法handleDelete()
         -->
        <template slot-scope="scope">
          <el-button
            size="mini"
            @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
          <!--
              scope.$index: 代表正在遍历集合中元素的索引，从0开始
              scope.row： 代表正在遍历的元素，表格在生成，遍历的是teacherList，
              所以row就表示teacherList集合中的当前行数据【也就是当前行Json对象】
              点击"编辑"、"删除"按钮时，编辑或删除当前行的数据
          -->
          <el-button
            size="mini"
            type="danger"
            @click="handleDelete(scope.$index, scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!--
       (g)第7步：为页面添加分页导航插件，使用ElementUI提供好的模板
      【:】是【v-bind】的缩写，单绑
      v-on:（等同于@），用来绑定事件
      使用的Vue语法，会被Vue对象进行解析
      :page-size="size" 表示将Vue对象data属性里面的size，赋值[绑定]给page-size
      当size发生改变时，会触发事件handleSizeChange
      当current发生改变时，会触发事件handleCurrentChange
      我们需要为这两个事件提供相应的方法
    -->
    <el-pagination
      :current-page="current"
      :page-sizes="[1, 3, 5, 10]"
      :page-size="size"
      :total="total"
      style="text-align:right;margin-top:20px"
      layout="total, sizes, prev, pager, next, jumper"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"/>
  </div>
</template>
<script>
// 引入api中的teacher.js，teacherApi是一个变量名，@表示src
import teacherApi from '@/api/teacher'
export default { // 相当于之前的new Vue({})
  data() {
    return {
      // ① 第3.1步：在Vue对象的data属性，声明一个变量来接收响应对象中的响应体【Json数组】
      teacherList: [],
      // (b)第2步：定义分页查询的参数
      teacherQuery: {}, // 封装分页的查询条件
      current: 1, // 指定分页的默认当前页码
      size: 3, // 指定分页的默认每页显示记录数
      total: 0, // 指定分页的默认总数
      multipleSelection: [] // 收集用户选中选择框信息，用于批量删除
    }
  },
  // （2）第二步：使用Vue生命周期的钩子函数created ()，页面打开直接加载getTeacherList()，发送请求加载数据
  created() {
    // 一定要加this，表示调用的是Vue对象中声明的方法[函数]
    // this.getTeacherList() 不加载查询所有讲师的方法，而是使用带条件分页查询【因为里面也带了查询所有】
    // (c)第3步：页面加载，直接加载分页查询方法
    this.getTeacherPage()
  },
  methods: {
    // 当点击【批量删除】按钮时，触发的事件
    batchRemove() {
      // 主要做两步：一是调用api，向后端发送请求；二是从this.multipleSelection中获取选择框中的id，传给api方法
      // 首先，multipleSelection: []，所以在遍历取出id之前，先判断里面的元素是不是为空，也就是用户没有选择选择框
      if (this.multipleSelection.length === 0) {
        // 给用户提示
        this.$message.warning('请选择要删除的讲师！')
        // 结束方法
        return
      }
      // 其次对multipleSelection: []进行遍历，取出里面的id
      this.$confirm(`此操作将永久删除讲师, 是否继续?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => { // 当用户点击确定时，对multipleSelection: []进行遍历，取出里面的id，像后端发送请求
        // 定义一个数组，来接受遍历得到的id数组
        var idList = []
        for (var i = 0; i < this.multipleSelection.length; i++) {
          // 取出id，往idList添加
          idList.push(this.multipleSelection[i].id)
        }
        // 打印测试idList里面是否添加元素成功
        console.log(idList)
        // 调用api，往后端发送批量删除请求
        teacherApi.teacherBatchDelete(idList)
          .then(response => {
            this.$message({
              type: 'success',
              message: '删除成功!'
            })
            /*
            但是提供用户删除成功后，我们还希望页面数据也得刷新一下，
            将删除后的数据重新显示在页面上，也就是调用getTeacherPage()
            重新向后端发送分页查询即可
          */
            this.getTeacherPage()
          })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        })
      })
    },

    // 批量删除，选择框发生改变时触发的函数，这个主要是收集用户选中选择框的行数据，里面封装了每行对应的id
    handleSelectionChange(val) {
      // console.log(val)
      // 经过打印测试，可以得知：val代表选中的行对应的json对象的集合，我们只需要遍历集合获取每一行元素的id，提交个后端批量删除即可
      // 将val赋值给multipleSelection: []，这样multipleSelection就有了每一行元素的id了
      this.multipleSelection = val
    },

    // 编辑按钮的单击事件[上面表格中，会传过来两个参数index, row]，可以接收，然后打印一下
    // teacher接收的是row，变量名，任意取，见名知意
    handleEdit(index, teacher) {
      // 对表格传过来的数据，进行打印测试
      // console.log(index)
      // console.log(teacher)
      // 在浏览器中测试可以得知，teacher中已经封装了当前行的id，所以可以根据id进行编辑当前行的数据了
      /**
       * 编辑讲师的实现步骤：
       *    1、点击list.vue页面中的编辑按钮，携带要编辑的讲师id，通过路由的方式，跳转到form.vue页面
       *    2、在form.vue页面中，根据讲师id，查询讲师信息进行回显
       *    3、用户修改讲师信息后，点击提交按钮，提交更新请求
       */
      /**
       * （一）第一步：当用户点击【编辑】按钮时，会回调handleEdit()函数；
       *              在该函数里面，通过路由的方式，跳转到新增讲师的页面【编辑和新增共用一个页面】
       * 在src/router/index.js中，已经定义好路由'edit/:id'，跳转到'@/views/teacher/form'
       * 我们跳转到form.vue页面时，要携带一个参数id过去，这样才能查询进行回显
       * 不然form.vue页面不知道是哪一行数据上的【编辑】按钮被点击跳转过来的
       * this.$router 表示获取路由对象【也就是src/router/index.js中整个路由】
       * this.$route  表示获取当前页面的单个路由【也就是src/router/index.js里面的单个路由】
       * `teacher/edit/${teacher.id}`
       * 表示跳转到teacher路由下的子路由edit，然后将表格传过来的teacher.id进行获取，一起跳转到form.vue页面
       * 'edit/:id' 表示获取跳转过来携带的id,:属于Vue语法，进行单绑
       */
      this.$router.push(`/teacher/edit/${teacher.id}`)
      /*
       （二）第二步：在api的teacher.js中，提供根据id查询讲师、更新讲师这两个函数
       （三）第三步：在form.vue页面，获取【编辑】按钮路由过去的id，来查询讲师信息，进行回显
                    涉及两个方法：teacherById(id) {}、created() {}
       （四）第四步：编写update(){}方法，向后台发送请求，进行更新数据，基本save(){}一样
       （五）第五步：在【提交】按钮的单击响应事件的方法中saveOrUpdate()，对填写的数据进行判断
                    如果是新增讲师，则走save(){}方法；
                    如果是编辑讲师，则走update(){}方法
                    怎么判断？根据id来判断，因为编辑更新讲师，是根据id来更新
                    如果没有id，就表示添加
                    如果存在id，就表示编辑
       （六）第六步：组件重用问题，参考课件
      */
    },

    // 删除按钮的单击事件
    handleDelete(index, teacher) {
      // 对表格传过来的数据，进行打印测试
      // console.log(index)
      // console.log(teacher)
      // 在浏览器中测试可以得知，teacher中已经封装了当前行的id，所以可以根据id进行删除当前行的数据了
      // 当用户点击【删除】按钮时，给一个友好提示，可以使用ElementUI提供好的模板，从MessageBox 弹框拿现成的
      // 要动态取值的地方，一定要使用ES6的模板字符串，也就是反单引号``
      this.$confirm(`此操作将永久删除${teacher.name}, 是否继续?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        /*
        当用户再次点击弹框中'确定'时，才开始向后端发送请求，删除指定行数据
        */
        // a、第(1)步：调用api，向后端发送请求，并传入需要的参数id【已经封装在表格传过来的row，也就是teacher中】
        teacherApi.teacherDelete(teacher.id).then(response => {
          this.$message({
            type: 'success',
            message: `删除${teacher.name}成功!`
          })
          /*
            但是提供用户删除成功后，我们还希望页面数据也得刷新一下，
            将删除后的数据重新显示在页面上，也就是调用getTeacherPage()
            重新向后端发送分页查询即可
          */
          this.getTeacherPage()
        })
        /*
        【知识拓展】涉及异步请求
        这里还存在一个问题，就是现在我们发的是axios异步请求，
        消息提示和重新刷新页面，如果是放在then(response => {})里面执行
        是可以正常执行的，但是假设代码变成这样：
        也就是将消息提示和重新刷新页面，放在异步请求的代码后面
        ---------------------------------------------------------------------
        teacherApi.teacherDelete(teacher.id).then(response => {
        })
        this.$message({
            type: 'success',
            message: `删除${teacher.name}成功!`
          })
        this.getTeacherPage()
        ---------------------------------------------------------------------
        就会出现一个问题，当我们点击【删除】按钮向后端发送异步请求：
        teacherApi.teacherDelete(teacher.id).then(response => {})
        还没等到返回请求的响应结果，就已经往下执行下面的代码了：
        this.$message({
            type: 'success',
            message: `删除${teacher.name}成功!`
          })
        this.getTeacherPage()
        也就是还没返回响应结果，就立马会给出提示信息，并且重新刷新页面
        但经过测试，实际上页面还是会显示所删除的当前行数据
        ---------------------------------------------------------------------
        为什么呢？
        因为this.getTeacherPage()刷新的列表数据，还是原来的列表数据
        异步请求是发出去了，但结果还没返回来呢，就开始往下执行下面的代码了
        因为前后端数据交互的时间
        肯定是要晚于this.getTeacherPage()执行时的时间的
        就像java中的主线程和子线程
        主线程往下执行代码，执行到teacherApi.teacherDelete，开了一个子线程发送请求
        然后继续往下执行代码，子线程发送请求到底怎么样了，只能手动刷新页面才能知道
        只有我们手动再刷新页面时，页面才会将删除的数据从页面中剔除掉，也就是得到请求返回的结果
        */
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        })
      })
    },

    // (j)第10步：为查询、清空两个按钮，绑定单击响应事件，也就是为query、clear提供相应的方法
    query() {
      // 当点击查询按钮时，提交带条件的分页查询
      this.getTeacherPage()
    },
    clear() {
      // 当点击清空按钮时，先将条件清空，然后将分页当前页码、每页记录数恢复到默认值，然后掉用分页查询方法
      this.teacherQuery = {}// 封装分页的查询条件
      this.current = 1 // 指定分页的默认当前页码
      this.size = 3 // 指定分页的默认每页显示记录数
      this.getTeacherPage()
    },
    // 当size发生改变时，会触发事件handleSizeChange
    handleSizeChange(size) {
      // console.log(`每页 ${size} 条`)
      // 当size发生改变时,重新查询分页数据，进行显示
      // ① 将改变的size，赋值data中this.size，这样data会渲染到div容器中
      this.size = size
      // ② 重新查询分页数据
      this.getTeacherPage()
    },

    // 当current发生改变时，会触发事件handleCurrentChange
    handleCurrentChange(current) {
      // console.log(`当前页: ${current}`)
      // 当current发生改变时,重新查询分页数据，进行显示
      // ① 将改变的current，赋值data中this.current，这样data会渲染到div容器中
      this.current = current
      // ② 重新查询分页数据
      this.getTeacherPage()
    },

    // 1、查询所有讲师
    getTeacherList() {
      // （1）第一步：引入api中的teacher.js，调用api中的方法，向后端发送axios异步请求
      teacherApi.teacherList()
        /*
        当请求成功时，走then函数
        response是一个变量值，可以随意取名，是当请求发送成功时，调用then()函数，会自动接收
        并封装响应对象到response
        可以对它进行打印测试，看它有没有接收响应对象成功
        因为请求失败，已经被utils/request.js中的response 拦截器处理了，所以此处只考虑请求成功
        */
        .then(response => {
          // 对返回来的响应对象进行打印测试
          /*
           通过浏览器F12的Console代码调试，可以得知，response已经成功接收到响应对象
           之前是response.data.data.items才拿到讲师列表数据
           但是在utils/request.js的 response 拦截器中，已经做了处理：
           return response.data
           也就是现在response.data.items就可以拿到讲师列表数据
           可以通过分析浏览器Console上的数据
          */
          // console.log(response)
          // 打印讲师列表数据
          console.log(response.data.items)
          /*
           （3）第三步：
           将获取到的所有讲师的Json数据，赋值给Vue对象的data属性，这样Vue就会自动帮我们
           在div容器中进行列表渲染，显示数据
           ① 第3.1步：在Vue对象的data属性，声明一个变量来接收响应对象中的响应体【Json数组】
           ② 第3.2步：使用response.data.items赋值给该变量
          */
          this.teacherList = response.data.items
        })
    },
    // 2、带条件分页查询
    getTeacherPage() {
      /*
       (a)第1步：
       调用api，向后端发送请求，并传入三个参数：current, size, teacherQuery
       可以在Vue对象的data属性进行设置，并给定默认值
       假设用户没有填写，则使用默认值进行查询
       (b)第2步：在Vue对象的data属性定义分页查询的参数
       (c)第3步：使用钩子函数created ()直接调用此函数，页面加载，直接进行查询
      */
      teacherApi.teacherPage(this.current, this.size, this.teacherQuery)
        // (d)第4步：当查询成功时，走then()函数，对拿到的数据进行处理
        .then(response => {
          /*
           (e)第5步：打印response，测试是否能拿到数据
           通过浏览器F12的Console代码调试，可以得知，分页数据封装在：
           response.data.page.records
          */
          console.log(response)

          // (f)第6步：将分页数据，赋值给可以封装列表数据的teacherList: []，然后渲染给div容器，进行页面展示
          this.teacherList = response.data.page.records

          // (g)第7步：为页面添加分页导航插件，使用ElementUI提供好的模板，在该模板中，还提供了总数total，所以也得获取然后赋值
          this.total = response.data.page.total

          /*
          (h)第8步：
          当size发生改变时，会触发事件handleSizeChange
          当current发生改变时，会触发事件handleCurrentChange
          我们需要为这两个事件提供相应的方法
          -------------------------------------------------
          (I)第9步：
          为页面提供一个表单，用来让用户填写查询条件的信息的，使用ElementUI提供好的模板
          */
        })
    }
  }
}
</script>

